#include "JSONWrapperPGMFC.hpp"
#include "Libs/SimpleJSON/JSON.hpp"
#include "MiscUtils/TdrMisc/SEngine.h"

#include <stdio.h>
#include <Windows.h>
#include <string>
#include <iostream>
#include <process.h>

#define NATIVE_HANDLE_TYPE unsigned long long
#define ENABLE_PGMFC_LOG true

/*
From official example
*/
#include <stdio.h>
#include <Windows.h>
#include <string>
#include <iostream>
#include <process.h>

#include "pgmfc_c.h"

using namespace std;

static std::string snFromDetect = "";

/* Define functions prototype */
#pragma region MyRegion
typedef unsigned char(*dll_detect)(unsigned short ports[10]);
typedef unsigned char(*dlltz_detect)(unsigned short ports[10]);

typedef unsigned long long(*dll_initialize)(unsigned short nPort);
typedef unsigned long long(*dlltz_initialize)(unsigned short nPort);
typedef unsigned char(*dll_close)(unsigned long long handle);

typedef unsigned char(*dll_frimwareversion)(unsigned long long handle, unsigned char version[30]);


typedef unsigned char(*dll_getchannelcount)(unsigned long long handle, unsigned short* channels);
typedef unsigned char(*dll_getmoduleid)(unsigned long long handle, unsigned short* id, unsigned char channel);
typedef unsigned char(*dll_setmoduleid)(unsigned long long handle, unsigned short id, unsigned char channel);

typedef unsigned char(*dll_setparams)(unsigned long long handle, unsigned short channel, unsigned short type,
	float peak, float trough, float peroid, float duty, float runtime, bool normalopen);

typedef unsigned char(*dll_setparams_flowrate)(unsigned long long handle, unsigned short channel, unsigned short type,
	float peak, float trough, float peroid, float duty, float runtime, bool normalopen);

typedef unsigned char(*dll_startmonitor)(unsigned long long handle, unsigned short span);
typedef unsigned char(*dll_stopmonitor)(unsigned long long handle);

typedef unsigned char(*dll_purgeon)(unsigned long long handle, unsigned short channel, bool external);
typedef unsigned char(*dll_purgeoff)(unsigned long long handle, unsigned short channel, bool external);

typedef unsigned char(*dll_stopEmergency)(unsigned long long handle);

typedef unsigned char(*dll_checkAirTempPressure)(unsigned long long handle);
typedef unsigned char(*dll_controlValves)(unsigned long long handle, unsigned short channel, unsigned short idValve, bool bOpen);

typedef unsigned char(*dll_operateDigitalOutputs)(unsigned long long handle, unsigned short idPort,
	unsigned short type, unsigned short polarity, unsigned short period, unsigned short pulse);

typedef unsigned char(*dll_queryDigitalIOStates)(unsigned long long handle, unsigned short states[8]);

typedef unsigned char(*dll_checkFlowmeter)(unsigned long long handle, unsigned short channel);
typedef unsigned char(*dll_queryFlowmeterInfo)(unsigned long long handle, unsigned short channel, bool* connected, unsigned char smodel[20]);

typedef unsigned char(*dll_queryRotaryAddress)(unsigned long long handle, unsigned short switchType, unsigned short mountID, bool& connected);
typedef unsigned char(*dll_rotaryReset)(unsigned long long handle, unsigned short switchType, unsigned short mountID);
typedef unsigned char(*dll_queryRotaryCurPos)(unsigned long long handle, unsigned short switchType, unsigned short mountID, unsigned short& pos);
typedef unsigned char(*dll_rotarySwitchTo)(unsigned long long handle, unsigned short switchType, unsigned short mountID, unsigned short portID);

typedef unsigned char(*dll_getCurrentPressure)(unsigned long long handle, unsigned short channel, float* pressure, unsigned short* timestamp);
typedef unsigned char(*dll_getCurrentFlowrate)(unsigned long long handle, unsigned short channel, float* flowrate, unsigned short* timestamp);

typedef unsigned char(*dll_getCurFlowrate_Liquid)(unsigned long long handle, unsigned short channel, float* flowrate, unsigned short* timesstamp);
typedef unsigned char(*dll_getCurFlowtotalizer)(unsigned long long handle, unsigned short channel, float* flowtotalizer, unsigned short* timesstamp);

typedef unsigned char(*dll_queryChannelStatus1)(unsigned long long handle);
typedef unsigned char(*dll_queryChannelStatus2)(unsigned long long handle);
typedef unsigned char(*dll_getCurChannelInfo)(unsigned long long handle, int* pumpStatus, int* runTime, int* waveForm, float* maxValue, float* minValue);
#pragma endregion

HMODULE hDll = NULL;

/*
End of official example
*/

struct PGMFC_API {
	struct NativeCalls {
		NativeCalls();
		void loadFuncs();
		dll_detect mfcs_detect;
		//dlltz_detect tz_detetct = (dlltz_detect)GetProcAddress(hDll, "mfcstz_detect");

		dll_initialize mfcs_initialization;
		//dlltz_initialize tz_initialize = (dlltz_initialize)GetProcAddress(hDll, "mfcstz_initialization");

		dll_close mfcs_close;
		dll_frimwareversion mfcs_frimwareversion;

		dll_getchannelcount mfcs_getchannelscount;
		dll_getmoduleid mfcs_getmoduleid;
		dll_setmoduleid mfcs_setmoduleid;

		dll_setparams mfcs_set_params;
		dll_setparams_flowrate mfcs_set_params_flowrate;
		dll_startmonitor mfcs_monitor_start;
		dll_stopmonitor mfcs_monitor_stop;

		dll_purgeon mfcs_purge_on;
		dll_purgeoff mfcs_purge_off;

		dll_stopEmergency mfcs_stopEmergency;

		dll_checkAirTempPressure mfcs_checkAirTempPressure;
		dll_controlValves mfcs_controlValves;

		dll_operateDigitalOutputs mfcs_operateDigitalOutputs;

		dll_queryDigitalIOStates mfcs_queryDigitalIOStates;

		dll_checkFlowmeter mfcs_checkFlowmeter;
		dll_queryFlowmeterInfo mfcs_queryFlowmeterInfo;

		dll_queryRotaryAddress mfcs_queryRotaryAddress;
		dll_rotaryReset mfcs_rotaryReset;
		dll_queryRotaryCurPos mfcs_queryRotaryCurPos;
		dll_rotarySwitchTo mfcs_rotarySwitchTo;

		dll_getCurrentPressure mfcs_getCurPressure;
		dll_getCurrentFlowrate mfcs_getCurFlowrate;

		dll_getCurFlowrate_Liquid mfcs_getCurFlowrate_Liquid;
		dll_getCurFlowtotalizer mfcs_getCurFlowtotalizer;

		dll_queryChannelStatus1 mfcs_queryChannelStatus1;
		dll_queryChannelStatus2 mfcs_queryChannelStatus2;
		dll_getCurChannelInfo mfcs_getCurChannelInfo;
	};
	NativeCalls native;

	bool j_findInt(JSONObject* paras, int& idx, const wchar_t* name, TWrite2Txt& logger); int j_parseInt(JSONObject* paras, int& idx, const wchar_t* name, TWrite2Txt& logger);
	bool j_findFlt(JSONObject* paras, int& idx, const wchar_t* name, TWrite2Txt& logger); float j_parseFlt(JSONObject* paras, int& idx, const wchar_t* name, TWrite2Txt& logger);
	bool j_findBul(JSONObject* paras, int& idx, const wchar_t* name, TWrite2Txt& logger); bool j_parseBul(JSONObject* paras, int& idx, const wchar_t* name, TWrite2Txt& logger);

	void addCErrorCode(int code, JSONObject* obj, const wchar_t* name);
	void addCRErrorCode(int code, JSONObject* obj, const wchar_t* name);
	wstring translateCErr(int cErr, const wchar_t* name);
	wstring translateCRErr(int cRErr, const wchar_t* name);

	void mfcs_getchannelscount(NATIVE_HANDLE_TYPE nativeHandle, int& channelCountOut, JSONObject* errorOut);
	void mfcs_getmoduleid(NATIVE_HANDLE_TYPE nativeHandle, int& moduleidOut, JSONObject* errorOut);
	void mfcs_firmwareversion(NATIVE_HANDLE_TYPE nativeHandle, string& fmVersionOut, JSONObject* errorOut);

	void mfcs_set_params(NATIVE_HANDLE_TYPE nativeHandle, JSONObject* paras, JSONObject* dataOut, JSONObject* errorOut, wstring logFilename);
	void mfcs_set_params_flowrate(NATIVE_HANDLE_TYPE nativeHandle, JSONObject* paras,
		JSONObject* dataOut, JSONObject* errorOut, wstring logFilename);
	void mfcs_monitor_start(NATIVE_HANDLE_TYPE nativeHandle, JSONObject* paras, JSONObject* dataOut, JSONObject* errorOut, wstring logFilename);
	void mfcs_monitor_stop(NATIVE_HANDLE_TYPE nativeHandle, JSONObject* paras, JSONObject* dataOut, JSONObject* errorOut, wstring logFilename);
	void mfcs_purge_on(NATIVE_HANDLE_TYPE nativeHandle, JSONObject* paras, JSONObject* dataOut, JSONObject* errorOut, wstring logFilename);
	void mfcs_purge_off(NATIVE_HANDLE_TYPE nativeHandle, JSONObject* paras, JSONObject* dataOut, JSONObject* errorOut, wstring logFilename);
	void mfcs_stopEmergency(NATIVE_HANDLE_TYPE nativeHandle, JSONObject* paras, JSONObject* dataOut, JSONObject* errorOut, wstring logFilename);
	void mfcs_getCurPressure(NATIVE_HANDLE_TYPE nativeHandle, JSONObject* paras, JSONObject* dataOut, JSONObject* errorOut, wstring logFilename);
	void mfcs_getCurFlowrate(NATIVE_HANDLE_TYPE nativeHandle, JSONObject* paras, JSONObject* dataOut, JSONObject* errorOut, wstring logFilename);
	void mfcs_getCurFlowrate_Liquid(NATIVE_HANDLE_TYPE nativeHandle, JSONObject* paras, JSONObject* dataOut, JSONObject* errorOut, wstring logFilename);
	void mfcs_getCurFlowtotalizer(NATIVE_HANDLE_TYPE nativeHandle, JSONObject* paras, JSONObject* dataOut, JSONObject* errorOut, wstring logFilename);
	void mfcs_controlValves(NATIVE_HANDLE_TYPE nativeHandle, JSONObject* paras, JSONObject* dataOut, JSONObject* errorOut, wstring logFilename);
	void mfcs_operateDigitalOutputs(NATIVE_HANDLE_TYPE nativeHandle, JSONObject* paras, JSONObject* dataOut, JSONObject* errorOut, wstring logFilename);
	void mfcs_queryDigitalIOStates(NATIVE_HANDLE_TYPE nativeHandle, JSONObject* paras, JSONObject* dataOut, JSONObject* errorOut, wstring logFilename);
	void mfcs_queryFlowmeterInfo(NATIVE_HANDLE_TYPE nativeHandle, JSONObject* paras, JSONObject* dataOut, JSONObject* errorOut, wstring logFilename);
	void mfcs_queryRotaryAddress(NATIVE_HANDLE_TYPE nativeHandle, JSONObject* paras, JSONObject* dataOut, JSONObject* errorOut, wstring logFilename);
	void mfcs_rotaryReset(NATIVE_HANDLE_TYPE nativeHandle, JSONObject* paras, JSONObject* dataOut, JSONObject* errorOut, wstring logFilename);
	void mfcs_queryRotaryCurPos(NATIVE_HANDLE_TYPE nativeHandle, JSONObject* paras, JSONObject* dataOut, JSONObject* errorOut, wstring logFilename);
	void mfcs_rotarySwitchTo(NATIVE_HANDLE_TYPE nativeHandle, JSONObject* paras, JSONObject* dataOut, JSONObject* errorOut, wstring logFilename);
	void mfcs_queryChannelStatus1(NATIVE_HANDLE_TYPE nativeHandle, JSONObject* paras, JSONObject* dataOut, JSONObject* errorOut, wstring logFilename);
	void mfcs_queryChannelStatus2(NATIVE_HANDLE_TYPE nativeHandle, JSONObject* paras, JSONObject* dataOut, JSONObject* errorOut, wstring logFilename);
	void mfcs_getCurChannelInfo(NATIVE_HANDLE_TYPE nativeHandle, JSONObject* paras, JSONObject* dataOut, JSONObject* errorOut, wstring logFilename);
};

PGMFC_API::NativeCalls::NativeCalls() {
	loadFuncs();
}

void PGMFC_API::NativeCalls::loadFuncs() {
	mfcs_detect = (dll_detect)GetProcAddress(hDll, "mfcs_detect");
	//dlltz_detect tz_detetct = (dlltz_detect)GetProcAddress(hDll, "mfcstz_detect");

	mfcs_initialization = (dll_initialize)GetProcAddress(hDll, "mfcs_initialization");
	//dlltz_initialize tz_initialize = (dlltz_initialize)GetProcAddress(hDll, "mfcstz_initialization");

	mfcs_close = (dll_close)GetProcAddress(hDll, "mfcs_close");
	mfcs_frimwareversion = (dll_frimwareversion)GetProcAddress(hDll, "mfcs_frimwareversion");

	mfcs_getchannelscount = (dll_getchannelcount)GetProcAddress(hDll, "mfcs_getchannelscount");
	mfcs_getmoduleid = (dll_getmoduleid)GetProcAddress(hDll, "mfcs_getmoduleid");
	mfcs_setmoduleid = (dll_setmoduleid)GetProcAddress(hDll, "mfcs_setmoduleid");

	mfcs_set_params = (dll_setparams)GetProcAddress(hDll, "mfcs_set_params");
	mfcs_set_params_flowrate = (dll_setparams_flowrate)GetProcAddress(hDll, "mfcs_set_params_flowrate");
	mfcs_monitor_start = (dll_startmonitor)GetProcAddress(hDll, "mfcs_monitor_start");
	mfcs_monitor_stop = (dll_stopmonitor)GetProcAddress(hDll, "mfcs_monitor_stop");

	mfcs_purge_on = (dll_purgeon)GetProcAddress(hDll, "mfcs_purge_on");
	mfcs_purge_off = (dll_purgeoff)GetProcAddress(hDll, "mfcs_purge_off");

	mfcs_stopEmergency = (dll_stopEmergency)GetProcAddress(hDll, "mfcs_stopEmergency");

	mfcs_checkAirTempPressure = (dll_checkAirTempPressure)GetProcAddress(hDll, "mfcs_checkAirTempPressure");
	mfcs_controlValves = (dll_controlValves)GetProcAddress(hDll, "mfcs_controlValves");

	mfcs_operateDigitalOutputs = (dll_operateDigitalOutputs)GetProcAddress(hDll, "mfcs_operateDigitalOutputs");

	mfcs_queryDigitalIOStates = (dll_queryDigitalIOStates)GetProcAddress(hDll, "mfcs_queryDigitalIOStates");

	mfcs_checkFlowmeter = (dll_checkFlowmeter)GetProcAddress(hDll, "mfcs_checkFlowmeter");
	mfcs_queryFlowmeterInfo = (dll_queryFlowmeterInfo)GetProcAddress(hDll, "mfcs_queryFlowmeterInfo");

	mfcs_queryRotaryAddress = (dll_queryRotaryAddress)GetProcAddress(hDll, "mfcs_queryRotaryAddress");
	mfcs_rotaryReset = (dll_rotaryReset)GetProcAddress(hDll, "mfcs_rotaryReset");
	mfcs_queryRotaryCurPos = (dll_queryRotaryCurPos)GetProcAddress(hDll, "mfcs_queryRotaryCurPos");
	mfcs_rotarySwitchTo = (dll_rotarySwitchTo)GetProcAddress(hDll, "mfcs_rotarySwitchTo");

	mfcs_getCurPressure = (dll_getCurrentPressure)GetProcAddress(hDll, "mfcs_getCurPressure");
	mfcs_getCurFlowrate = (dll_getCurrentFlowrate)GetProcAddress(hDll, "mfcs_getCurFlowrate");

	mfcs_getCurFlowrate_Liquid = (dll_getCurFlowrate_Liquid)GetProcAddress(hDll, "mfcs_getCurFlowrate_Liquid");
	mfcs_getCurFlowtotalizer = (dll_getCurFlowtotalizer)GetProcAddress(hDll, "mfcs_getCurFlowtotalizer");

	mfcs_queryChannelStatus1 = (dll_queryChannelStatus1)GetProcAddress(hDll, "mfcs_queryChannelStatus1");
	mfcs_queryChannelStatus2 = (dll_queryChannelStatus2)GetProcAddress(hDll, "mfcs_queryChannelStatus2");
	mfcs_getCurChannelInfo = (dll_getCurChannelInfo)GetProcAddress(hDll, "mfcs_getCurChannelInfo");
}

PGMFC_API* api = nullptr;
NATIVE_HANDLE_TYPE* tempInitHandle = nullptr;
//std::map<void*, unsigned short> handle2serialMap;

int JsonWrapperPGMFC::loadLibrary(int flag) {
	//return PGMFC_Native::init();
	if (api == nullptr) {
		//hDll = LoadLibrary(L"pgmfc_64_d.dll");
		hDll = LoadLibrary(L"pgmfc_64.dll");
		if (!hDll)
		{
			return -2;
		}
		api = new PGMFC_API();
	}
	if (flag == 1) {
		return 1;
	}
	return tempLoad();
}

int JsonWrapperPGMFC::tempLoad() {
	if (tempInitHandle != nullptr) {
		return true;
	}
	for (int idx = 0; idx < 5; idx++) {
		void* handle = connect();
		if (handle != nullptr) {
			tempInitHandle = (NATIVE_HANDLE_TYPE*)handle;
			string comment = "Connect PGMFC at start success";
			TLogger::writeLine(comment);
			cout << comment << endl;
			return 1;
		}
	}
	string comment = "Cannot Connect PGMFC at start";
	TLogger::writeLine(comment);
	cout << comment << endl;
	return -10;
}

void* JsonWrapperPGMFC::connect() {
	if (tempInitHandle != nullptr) {
		return tempInitHandle;
	}
	//PGMFC_Native::init();

	//handle2serialMap.
	//unsigned short validControllers[20] = { 0 };
	//int validCount = PGMFC_Native::mfcs_detect(validControllers);
	//validCount = 1;
	//validControllers[0] = 7;
	//if (validCount > 0) {
	//	NATIVE_HANDLE_TYPE handle = PGMFC_Native::mfcs_initialization(validControllers[0]);
	//	if (handle > 0) {
	//		NATIVE_HANDLE_TYPE* ret = new NATIVE_HANDLE_TYPE[1];
	//		*ret = handle;
	//		return ret;
	//	}
	//	TLogger::writeLine("[PGMFC core] Not valid port " + TFormater::int2str(validControllers[0]));
	//	validCount = PGMFC_Native::mfcs_detect(validControllers);
	//	validCount = PGMFC_Native::mfcs_detect(validControllers);
	//	validCount = PGMFC_Native::mfcs_detect(validControllers);
	//}
	//else {
	//	TLogger::writeLine("[PGMFC core] No port");
	//}
	////PGMFC_Native::release();
	//return nullptr;

	//return nullptr;
	{
		unsigned short validControllers[100] = { 0 };
		//dll_detect mfcs_detect = (dll_detect)GetProcAddress(hDll, "mfcs_detect");
		//unsigned char validPortX = mfcs_detect(validControllers);

		//dll_initialize mfcs_initialization = (dll_initialize)GetProcAddress(hDll, "mfcs_initialization");
		int validCount = api->native.mfcs_detect(validControllers);
		int port = validControllers[0];
		NATIVE_HANDLE_TYPE handle = NULL, handleX = NULL;  // Local instrument handle
		if (validCount > 0 && port > 0 && port < 100) {
			handle = api->native.mfcs_initialization(port);
			//handleX = api->native.mfcs_initialization(port);
		}
		if (handle == NULL) {
			TLogger::writeLine("[PGMFC core] Not valid port " + TFormater::int2str(port));
			return nullptr;
		}

		NATIVE_HANDLE_TYPE* ret = new NATIVE_HANDLE_TYPE[1];
		*ret = handle;

		snFromDetect = TFormater::int2str(validControllers[0]);

		return ret;
	}
}

void JsonWrapperPGMFC::disconnect(void* nativeHandle) {
	NATIVE_HANDLE_TYPE handle;
	if (nativeHandle == nullptr) {
		handle = NULL;
	}
	else {
		handle = *((NATIVE_HANDLE_TYPE*)nativeHandle);
	}
	//mfcs_close(handle);

	delete[] nativeHandle;
}

int JsonWrapperPGMFC::getSerialNo(void* nativeHandle, std::string& snOut, JSONObject* outputError) {
	if (nativeHandle == nullptr) {
		snOut = "NA";
		api->addCErrorCode(-1, outputError, L"mfcs_detect");
		return 0;
	}

	snOut = snFromDetect;

	return 1;
}

int JsonWrapperPGMFC::getChannelCount(void* nativeHandle, int& channelCountOut, JSONObject* outputError) {
	NATIVE_HANDLE_TYPE handle;
	if (nativeHandle == nullptr) {
		handle = NULL;
	}
	else {
		handle = *((NATIVE_HANDLE_TYPE*)nativeHandle);
	}

	api->mfcs_getchannelscount(handle, channelCountOut, outputError);

	return 1;
}

int JsonWrapperPGMFC::getModuleID(void* nativeHandle, int& moduleIDOut, JSONObject* outputError) {
	NATIVE_HANDLE_TYPE handle;
	if (nativeHandle == nullptr) {
		handle = NULL;
	}
	else {
		handle = *((NATIVE_HANDLE_TYPE*)nativeHandle);
	}

	api->mfcs_getmoduleid(handle, moduleIDOut, outputError);

	return 1;
}

int JsonWrapperPGMFC::getFirmwareVersion(void* nativeHandle, std::string& fmVerOut, JSONObject* outputError) {
	NATIVE_HANDLE_TYPE handle;
	if (nativeHandle == nullptr) {
		handle = NULL;
	}
	else {
		handle = *((NATIVE_HANDLE_TYPE*)nativeHandle);
	}

	api->mfcs_firmwareversion(handle, fmVerOut, outputError);

	return 1;
}

int JsonWrapperPGMFC::callFunction(void* nativeHandle, const wchar_t* functionName,
	JSONObject* inputParas,
	JSONObject* outputData,
	JSONObject* errorOut,
	std::wstring logFilename) {
	//TLogger::writeLine("JsonWrapperPGMFC::callFunction write to");
	//TLogger::writeLine(logFilename);
	NATIVE_HANDLE_TYPE handle;
	if (nativeHandle == nullptr) {
		handle = NULL;
	}
	else {
		handle = *((NATIVE_HANDLE_TYPE*)nativeHandle);
	}

	wstring funcName = functionName;
	if (funcName.compare(L"mfcs_set_params") == 0) {
		api->mfcs_set_params(handle, inputParas,
			outputData, errorOut, logFilename);
	}
	else 	if (funcName.compare(L"mfcs_set_params_flowrate") == 0) {
		api->mfcs_set_params_flowrate(handle, inputParas,
			outputData, errorOut, logFilename);
	}
	else 	if (funcName.compare(L"mfcs_monitor_start") == 0) {
		api->mfcs_monitor_start(handle, inputParas,
			outputData, errorOut, logFilename);
	}
	else 	if (funcName.compare(L"mfcs_monitor_stop") == 0) {
		api->mfcs_monitor_stop(handle, inputParas,
			outputData, errorOut, logFilename);
	}
	else 	if (funcName.compare(L"mfcs_purge_on") == 0) {
		api->mfcs_purge_on(handle, inputParas,
			outputData, errorOut, logFilename);
	}
	else 	if (funcName.compare(L"mfcs_purge_off") == 0) {
		api->mfcs_purge_off(handle, inputParas,
			outputData, errorOut, logFilename);
	}
	else 	if (funcName.compare(L"mfcs_stopEmergency") == 0) {
		api->mfcs_stopEmergency(handle, inputParas,
			outputData, errorOut, logFilename);
	}
	else 	if (funcName.compare(L"mfcs_getCurPressure") == 0) {
		api->mfcs_getCurPressure(handle, inputParas,
			outputData, errorOut, logFilename);
	}
	else 	if (funcName.compare(L"mfcs_getCurFlowrate") == 0) {
		api->mfcs_getCurFlowrate(handle, inputParas,
			outputData, errorOut, logFilename);
	}
	else 	if (funcName.compare(L"mfcs_getCurFlowrate_Liquid") == 0) {
		api->mfcs_getCurFlowrate_Liquid(handle, inputParas,
			outputData, errorOut, logFilename);
	}
	else 	if (funcName.compare(L"mfcs_getCurFlowtotalizer") == 0) {
		api->mfcs_getCurFlowtotalizer(handle, inputParas,
			outputData, errorOut, logFilename);
	}
	else 	if (funcName.compare(L"mfcs_controlValves") == 0) {
		api->mfcs_controlValves(handle, inputParas,
			outputData, errorOut, logFilename);
	}
	else 	if (funcName.compare(L"mfcs_operateDigitalOutputs") == 0) {
		api->mfcs_operateDigitalOutputs(handle, inputParas,
			outputData, errorOut, logFilename);
	}
	else 	if (funcName.compare(L"mfcs_queryDigitalIOStates") == 0) {
		api->mfcs_queryDigitalIOStates(handle, inputParas,
			outputData, errorOut, logFilename);
	}
	else 	if (funcName.compare(L"mfcs_queryFlowmeterInfo") == 0) {
		api->mfcs_queryFlowmeterInfo(handle, inputParas,
			outputData, errorOut, logFilename);
	}
	else 	if (funcName.compare(L"mfcs_queryRotaryAddress") == 0) {
		api->mfcs_queryRotaryAddress(handle, inputParas,
			outputData, errorOut, logFilename);
	}
	else 	if (funcName.compare(L"mfcs_rotaryReset") == 0) {
		api->mfcs_rotaryReset(handle, inputParas,
			outputData, errorOut, logFilename);
	}
	else 	if (funcName.compare(L"mfcs_queryRotaryCurPos") == 0) {
		api->mfcs_queryRotaryCurPos(handle, inputParas,
			outputData, errorOut, logFilename);
	}
	else 	if (funcName.compare(L"mfcs_rotarySwitchTo") == 0) {
		api->mfcs_rotarySwitchTo(handle, inputParas,
			outputData, errorOut, logFilename);
	}
	else 	if (funcName.compare(L"mfcs_queryChannelStatus1") == 0) {
		api->mfcs_queryChannelStatus1(handle, inputParas,
			outputData, errorOut, logFilename);
	}
	else 	if (funcName.compare(L"mfcs_queryChannelStatus2") == 0) {
		api->mfcs_queryChannelStatus2(handle, inputParas,
			outputData, errorOut, logFilename);
	}
	else 	if (funcName.compare(L"mfcs_getCurChannelInfo") == 0) {
		api->mfcs_getCurChannelInfo(handle, inputParas,
			outputData, errorOut, logFilename);
	}
	else {
		TLogger::writeLine("Function not found: ");
		TLogger::writeLine(funcName);
	}

	return 1;
}

void PGMFC_API::mfcs_getchannelscount(NATIVE_HANDLE_TYPE nativeHandle, int& channelCountOut, JSONObject* errorOut) {
	int error;
	if (nativeHandle != NULL) {
		unsigned short _channelCount;
		error = native.mfcs_getchannelscount(nativeHandle, &_channelCount);
		channelCountOut = _channelCount;
	}
	else {
		// not connected
		error = -1;
	}
	addCErrorCode(error, errorOut, L"mfcs_getchannelscount");
}

// channel is the channel number (same module id for 1-2, or 3 - 4)
void PGMFC_API::mfcs_getmoduleid(NATIVE_HANDLE_TYPE nativeHandle, int& moduleidOut, JSONObject* errorOut) {
	int error;
	if (nativeHandle != NULL) {
		unsigned short _channelCount, modID0 = 0, modID1 = 0;
		error = native.mfcs_getchannelscount(nativeHandle, &_channelCount);
		if (error == 0) {
			if (_channelCount >= 2) {
				error = native.mfcs_getmoduleid(nativeHandle, &modID0, 0);
			}
			if (_channelCount >= 4) {
				error = native.mfcs_getmoduleid(nativeHandle, &modID1, 1);
			}
			moduleidOut = modID0;
		}
	}
	else {
		// not connected
		error = -1;
	}
	addCErrorCode(error, errorOut, L"mfcs_getchannelscount");
}

void PGMFC_API::mfcs_firmwareversion(NATIVE_HANDLE_TYPE nativeHandle, string& fmVersionOut, JSONObject* errorOut) {
	int error;
	if (nativeHandle != NULL) {
		unsigned char fmRaw[30] = {0};
		error = native.mfcs_frimwareversion(nativeHandle, fmRaw);
		if (error == 0) {
			fmVersionOut = string((char*)fmRaw);
		}
	}
	else {
		// not connected
		error = -1;
	}
	addCErrorCode(error, errorOut, L"mfcs_getchannelscount");
}

void PGMFC_API::mfcs_set_params(NATIVE_HANDLE_TYPE nativeHandle, JSONObject* paras,
	JSONObject* dataOut, JSONObject* errorOut, wstring logFilename) {
	// not used
	TWrite2Txt logger(logFilename, ENABLE_PGMFC_LOG);
	logger.writeString("[PGMFC core] mfcs_set_params(");

	int paraIdx = 0;
	if (!j_findInt(paras, paraIdx, L"channel", logger)) { return; } int channel = j_parseInt(paras, paraIdx, L"channel", logger);
	if (!j_findInt(paras, paraIdx, L"type", logger)) { return; } int type = j_parseInt(paras, paraIdx, L"type", logger);
	if (!j_findFlt(paras, paraIdx, L"peak", logger)) { return; } float peak = j_parseFlt(paras, paraIdx, L"peak", logger);
	if (!j_findFlt(paras, paraIdx, L"trough", logger)) { return; } float trough = j_parseFlt(paras, paraIdx, L"trough", logger);
	if (!j_findFlt(paras, paraIdx, L"period", logger)) { return; } float period = j_parseFlt(paras, paraIdx, L"period", logger);
	if (!j_findFlt(paras, paraIdx, L"duty", logger)) { return; } float duty = j_parseFlt(paras, paraIdx, L"duty", logger);
	if (!j_findFlt(paras, paraIdx, L"runtime", logger)) { return; } float runtime = j_parseFlt(paras, paraIdx, L"runtime", logger);
	if (!j_findBul(paras, paraIdx, L"normalopen", logger)) { return; } bool normalopen = j_parseBul(paras, paraIdx, L"normalopen", logger);

	logger.writeLine(")");

	int error;
	if (nativeHandle != NULL) {
		error = native.mfcs_set_params(nativeHandle, channel, type, peak, trough, period, duty, runtime, normalopen);
	}
	else {
		// not connected
		error = -1;
	}
	addCErrorCode(error, errorOut, L"mfcs_set_params");
}

void PGMFC_API::mfcs_set_params_flowrate(NATIVE_HANDLE_TYPE nativeHandle, JSONObject* paras,
	JSONObject* dataOut, JSONObject* errorOut, wstring logFilename) {
	TWrite2Txt logger(logFilename, ENABLE_PGMFC_LOG);
	logger.writeString("[PGMFC core] mfcs_set_params_flowrate(");

	int paraIdx = 0;
	if (!j_findInt(paras, paraIdx, L"channel", logger)) { return; } int channel = j_parseInt(paras, paraIdx, L"channel", logger);
	if (!j_findInt(paras, paraIdx, L"type", logger)) { return; } int type = j_parseInt(paras, paraIdx, L"type", logger);
	if (!j_findFlt(paras, paraIdx, L"peak", logger)) { return; } float peak = j_parseFlt(paras, paraIdx, L"peak", logger);
	if (!j_findFlt(paras, paraIdx, L"trough", logger)) { return; } float trough = j_parseFlt(paras, paraIdx, L"trough", logger);
	if (!j_findFlt(paras, paraIdx, L"period", logger)) { return; } float period = j_parseFlt(paras, paraIdx, L"period", logger);
	if (!j_findFlt(paras, paraIdx, L"duty", logger)) { return; } float duty = j_parseFlt(paras, paraIdx, L"duty", logger);
	if (!j_findFlt(paras, paraIdx, L"runtime", logger)) { return; } float runtime = j_parseFlt(paras, paraIdx, L"runtime", logger);
	if (!j_findBul(paras, paraIdx, L"normalopen", logger)) { return; } bool normalopen = j_parseBul(paras, paraIdx, L"normalopen", logger);

	logger.writeLine(")");

	int error;
	if (nativeHandle != NULL) {
		error = native.mfcs_set_params_flowrate(nativeHandle, channel, type, peak, trough, period, duty, runtime, normalopen);
	}
	else {
		// not connected
		error = -1;
	}
	addCErrorCode(error, errorOut, L"mfcs_set_params_flowrate");
}

void PGMFC_API::mfcs_monitor_start(NATIVE_HANDLE_TYPE nativeHandle, JSONObject* paras,
	JSONObject* dataOut, JSONObject* errorOut, wstring logFilename) {
	TWrite2Txt logger(logFilename, ENABLE_PGMFC_LOG);
	logger.writeString("[PGMFC core] mfcs_monitor_start(");

	int paraIdx = 0;
	if (!j_findInt(paras, paraIdx, L"span", logger)) { return; } int span = j_parseInt(paras, paraIdx, L"span", logger);
	logger.writeLine(")");

	int error;
	if (nativeHandle != NULL) {
		error = native.mfcs_monitor_start(nativeHandle, span);
	}
	else {
		// not connected
		error = -1;
	}
	addCErrorCode(error, errorOut, L"mfcs_monitor_start");
}

void PGMFC_API::mfcs_monitor_stop(NATIVE_HANDLE_TYPE nativeHandle, JSONObject* paras,
	JSONObject* dataOut, JSONObject* errorOut, wstring logFilename) {
	TWrite2Txt logger(logFilename, ENABLE_PGMFC_LOG);
	logger.writeString("[PGMFC core] mfcs_monitor_stop(");
	logger.writeLine(")");

	int error;
	if (nativeHandle != NULL) {
		error = native.mfcs_monitor_stop(nativeHandle);
	}
	else {
		// not connected
		error = -1;
	}
	addCErrorCode(error, errorOut, L"mfcs_monitor_stop");
}

void PGMFC_API::mfcs_purge_on(NATIVE_HANDLE_TYPE nativeHandle, JSONObject* paras,
	JSONObject* dataOut, JSONObject* errorOut, wstring logFilename) {
	TWrite2Txt logger(logFilename, ENABLE_PGMFC_LOG);
	logger.writeString("[PGMFC core] mfcs_purge_on(");

	int paraIdx = 0;
	if (!j_findInt(paras, paraIdx, L"channel", logger)) { return; } int channel = j_parseInt(paras, paraIdx, L"channel", logger);
	if (!j_findBul(paras, paraIdx, L"external", logger)) { return; } bool external = j_parseBul(paras, paraIdx, L"external", logger);

	logger.writeLine(")");

	int error;
	if (nativeHandle != NULL) {
		error = native.mfcs_purge_on(nativeHandle, channel, external);
	}
	else {
		// not connected
		(*dataOut)[L"flowrate"] = new JSONValue(-100);
		(*dataOut)[L"timestamp"] = new JSONValue(-101);
		error = -1;
	}
	addCErrorCode(error, errorOut, L"mfcs_purge_on");
}

void PGMFC_API::mfcs_purge_off(NATIVE_HANDLE_TYPE nativeHandle, JSONObject* paras,
	JSONObject* dataOut, JSONObject* errorOut, wstring logFilename) {
	TWrite2Txt logger(logFilename, ENABLE_PGMFC_LOG);
	logger.writeString("[PGMFC core] mfcs_purge_off(");

	int paraIdx = 0;
	if (!j_findInt(paras, paraIdx, L"channel", logger)) { return; } int channel = j_parseInt(paras, paraIdx, L"channel", logger);
	if (!j_findBul(paras, paraIdx, L"external", logger)) { return; } bool external = j_parseBul(paras, paraIdx, L"external", logger);

	logger.writeLine(")");

	int error;
	if (nativeHandle != NULL) {
		error = native.mfcs_purge_off(nativeHandle, channel, external);
	}
	else {
		// not connected
		error = -1;
	}
	addCErrorCode(error, errorOut, L"mfcs_purge_off");
}

void PGMFC_API::mfcs_stopEmergency(NATIVE_HANDLE_TYPE nativeHandle, JSONObject* paras,
	JSONObject* dataOut, JSONObject* errorOut, wstring logFilename) {
	TWrite2Txt logger(logFilename, ENABLE_PGMFC_LOG);
	logger.writeString("[PGMFC core] mfcs_stopEmergency(");
	logger.writeLine(")");

	int error;
	if (nativeHandle != NULL) {
		error = native.mfcs_stopEmergency(nativeHandle);
	}
	else {
		// not connected
		error = -1;
	}
	addCErrorCode(error, errorOut, L"mfcs_stopEmergency");
}

void PGMFC_API::mfcs_getCurPressure(NATIVE_HANDLE_TYPE nativeHandle, JSONObject* paras,
	JSONObject* dataOut, JSONObject* errorOut, wstring logFilename) {
	TWrite2Txt logger(logFilename, ENABLE_PGMFC_LOG);
	logger.writeString("[PGMFC core] mfcs_getCurPressure(");

	int paraIdx = 0;
	if (!j_findInt(paras, paraIdx, L"channel", logger)) { return; } int channel = j_parseInt(paras, paraIdx, L"channel", logger);

	logger.writeLine(")");

	int error;
	if (nativeHandle != NULL) {
		float pressure;
		unsigned short timestamp;
		error = native.mfcs_getCurPressure(nativeHandle, channel, &pressure, &timestamp);
		(*dataOut)[L"pressure"] = new JSONValue(pressure);
		(*dataOut)[L"timestamp"] = new JSONValue(timestamp);
	}
	else {
		(*dataOut)[L"pressure"] = new JSONValue(-201);
		(*dataOut)[L"timestamp"] = new JSONValue(-202);
		// not connected
		error = -1;
	}
	addCErrorCode(error, errorOut, L"mfcs_getCurPressure");
}

void PGMFC_API::mfcs_getCurFlowrate(NATIVE_HANDLE_TYPE nativeHandle, JSONObject* paras,
	JSONObject* dataOut, JSONObject* errorOut, wstring logFilename) {
	TWrite2Txt logger(logFilename, ENABLE_PGMFC_LOG);
	logger.writeString("[PGMFC core] mfcs_getCurFlowrate(");

	int paraIdx = 0;
	if (!j_findInt(paras, paraIdx, L"channel", logger)) { return; } int channel = j_parseInt(paras, paraIdx, L"channel", logger);

	logger.writeLine(")");

	int error;
	if (nativeHandle != NULL) {
		float flowrate;
		unsigned short timestamp;
		error = native.mfcs_getCurFlowrate(nativeHandle, channel, &flowrate, &timestamp);
		(*dataOut)[L"flowrate"] = new JSONValue(flowrate);
		(*dataOut)[L"timestamp"] = new JSONValue(timestamp);
	}
	else {
		// not connected
		error = -1;
		(*dataOut)[L"flowrate"] = new JSONValue(-301);
		(*dataOut)[L"timestamp"] = new JSONValue(-302);
	}
	addCErrorCode(error, errorOut, L"mfcs_getCurFlowrate");
}

void PGMFC_API::mfcs_getCurFlowrate_Liquid(NATIVE_HANDLE_TYPE nativeHandle, JSONObject* paras,
	JSONObject* dataOut, JSONObject* errorOut, wstring logFilename) {
	TWrite2Txt logger(logFilename, ENABLE_PGMFC_LOG);
	logger.writeString("[PGMFC core] mfcs_getCurFlowrate_Liquid(");

	int paraIdx = 0;
	if (!j_findInt(paras, paraIdx, L"channel", logger)) { return; } int channel = j_parseInt(paras, paraIdx, L"channel", logger);

	logger.writeLine(")");

	int error;
	if (nativeHandle != NULL) {
		float flowrate;
		unsigned short timestamp;
		error = native.mfcs_getCurFlowrate_Liquid(nativeHandle, channel, &flowrate, &timestamp);
		(*dataOut)[L"flowrate"] = new JSONValue(flowrate);
		(*dataOut)[L"timestamp"] = new JSONValue(timestamp);
	}
	else {
		// not connected
		error = -1;
		(*dataOut)[L"flowrate"] = new JSONValue(-401);
		(*dataOut)[L"timestamp"] = new JSONValue(-402);
	}
	addCErrorCode(error, errorOut, L"mfcs_getCurFlowrate_Liquid");
}

void PGMFC_API::mfcs_getCurFlowtotalizer(NATIVE_HANDLE_TYPE nativeHandle, JSONObject* paras,
	JSONObject* dataOut, JSONObject* errorOut, wstring logFilename) {
	TWrite2Txt logger(logFilename, ENABLE_PGMFC_LOG);
	logger.writeString("[PGMFC core] mfcs_getCurFlowtotalizer(");

	int paraIdx = 0;
	if (!j_findInt(paras, paraIdx, L"channel", logger)) { return; } int channel = j_parseInt(paras, paraIdx, L"channel", logger);

	logger.writeLine(")");

	int error;
	if (nativeHandle != NULL) {
		float flowtotalizer;
		unsigned short timestamp;
		error = native.mfcs_getCurFlowtotalizer(nativeHandle, channel, &flowtotalizer, &timestamp);
		(*dataOut)[L"flowtotalizer"] = new JSONValue(flowtotalizer);
		(*dataOut)[L"timestamp"] = new JSONValue(timestamp);
	}
	else {
		// not connected
		(*dataOut)[L"flowtotalizer"] = new JSONValue(-501);
		(*dataOut)[L"timestamp"] = new JSONValue(-502);
		error = -1;
	}
	addCErrorCode(error, errorOut, L"mfcs_getCurFlowtotalizer");
}

void PGMFC_API::mfcs_controlValves(NATIVE_HANDLE_TYPE nativeHandle, JSONObject* paras,
	JSONObject* dataOut, JSONObject* errorOut, wstring logFilename) {
	TWrite2Txt logger(logFilename, ENABLE_PGMFC_LOG);
	logger.writeString("[PGMFC core] mfcs_controlValves(");

	int paraIdx = 0;
	if (!j_findInt(paras, paraIdx, L"channel", logger)) { return; } int channel = j_parseInt(paras, paraIdx, L"channel", logger);
	if (!j_findInt(paras, paraIdx, L"id_valves", logger)) { return; } int id_valves = j_parseInt(paras, paraIdx, L"id_valves", logger);
	if (!j_findBul(paras, paraIdx, L"b_open", logger)) { return; } bool b_open = j_parseBul(paras, paraIdx, L"b_open", logger);

	logger.writeLine(")");

	int error;
	if (nativeHandle != NULL) {
		float flowtotalizer;
		unsigned short timestamp;
		error = native.mfcs_controlValves(nativeHandle, channel, id_valves, b_open);
	}
	else {
		// not connected
		error = -1;
	}
	addCErrorCode(error, errorOut, L"mfcs_controlValves");
}

void PGMFC_API::mfcs_operateDigitalOutputs(NATIVE_HANDLE_TYPE nativeHandle, JSONObject* paras,
	JSONObject* dataOut, JSONObject* errorOut, wstring logFilename) {
	TWrite2Txt logger(logFilename, ENABLE_PGMFC_LOG);
	logger.writeString("[PGMFC core] mfcs_operateDigitalOutputs(");

	int paraIdx = 0;
	if (!j_findInt(paras, paraIdx, L"id_port", logger)) { return; } int id_port = j_parseInt(paras, paraIdx, L"id_port", logger);
	if (!j_findInt(paras, paraIdx, L"type", logger)) { return; } int type = j_parseInt(paras, paraIdx, L"type", logger);
	if (!j_findInt(paras, paraIdx, L"polarity", logger)) { return; } int polarity = j_parseInt(paras, paraIdx, L"polarity", logger);
	if (!j_findInt(paras, paraIdx, L"period", logger)) { return; } int period = j_parseInt(paras, paraIdx, L"period", logger);
	if (!j_findInt(paras, paraIdx, L"pulse", logger)) { return; } int pulse = j_parseInt(paras, paraIdx, L"pulse", logger);

	logger.writeLine(")");

	int error;
	if (nativeHandle != NULL) {
		float flowtotalizer;
		unsigned short timestamp;
		error = native.mfcs_operateDigitalOutputs(nativeHandle, id_port, type, polarity, period, pulse);
	}
	else {
		// not connected
		error = -1;
	}
	addCErrorCode(error, errorOut, L"mfcs_operateDigitalOutputs");
}

void PGMFC_API::mfcs_queryDigitalIOStates(NATIVE_HANDLE_TYPE nativeHandle, JSONObject* paras,
	JSONObject* dataOut, JSONObject* errorOut, wstring logFilename) {
	TWrite2Txt logger(logFilename, ENABLE_PGMFC_LOG);
	logger.writeString("[PGMFC core] mfcs_queryDigitalIOStates(");
	logger.writeLine(")");

	int error;
	if (nativeHandle != NULL) {
		unsigned short states[8];
		error = native.mfcs_queryDigitalIOStates(nativeHandle, states);
		JSONArray array;
		for (int idx = 0; idx < 8; idx++) {
			array.push_back(new JSONValue(states[idx]));
		}
		(*dataOut)[L"states"] = new JSONValue(array);
	}
	else {
		// not connected
		JSONArray array;
		for (int idx = 0; idx < 8; idx++) {
			array.push_back(new JSONValue(-idx - 10));
		}
		(*dataOut)[L"states"] = new JSONValue(array);
		error = -1;
	}
	addCErrorCode(error, errorOut, L"mfcs_queryDigitalIOStates");
}

void PGMFC_API::mfcs_queryFlowmeterInfo(NATIVE_HANDLE_TYPE nativeHandle, JSONObject* paras, JSONObject* dataOut, JSONObject* errorOut, wstring logFilename) {
	TWrite2Txt logger(logFilename, ENABLE_PGMFC_LOG);
	logger.writeString("[PGMFC core] mfcs_queryFlowmeterInfo(");

	int paraIdx = 0;
	if (!j_findInt(paras, paraIdx, L"channel", logger)) { return; } int channel = j_parseInt(paras, paraIdx, L"channel", logger);

	logger.writeLine(")");

	int error;
	if (nativeHandle != NULL) {
		bool connected;
		unsigned char model[20] = { 0 };
		error = native.mfcs_queryFlowmeterInfo(nativeHandle, channel, &connected, model);
		(*dataOut)[L"connected"] = new JSONValue(connected);
		(*dataOut)[L"model"] = new JSONValue(TFormater::string2wstring((char*)model));
	}
	else {
		// not connected
		(*dataOut)[L"connected"] = new JSONValue(false);
		(*dataOut)[L"model"] = new JSONValue(L"flowmeter model?");
		error = -1;
	}
	addCErrorCode(error, errorOut, L"mfcs_queryFlowmeterInfo");
}

void PGMFC_API::mfcs_queryRotaryAddress(NATIVE_HANDLE_TYPE nativeHandle, JSONObject* paras, JSONObject* dataOut, JSONObject* errorOut, wstring logFilename) {
	TWrite2Txt logger(logFilename, ENABLE_PGMFC_LOG);
	logger.writeString("[PGMFC core] mfcs_queryRotaryAddress(");

	int paraIdx = 0;
	if (!j_findInt(paras, paraIdx, L"switch_type", logger)) { return; } int switch_type = j_parseInt(paras, paraIdx, L"switch_type", logger);
	if (!j_findInt(paras, paraIdx, L"mount_id", logger)) { return; } int mount_id = j_parseInt(paras, paraIdx, L"mount_id", logger);

	logger.writeLine(")");

	int error;
	if (nativeHandle != NULL) {
		bool connected;
		error = native.mfcs_queryRotaryAddress(nativeHandle, switch_type, mount_id, connected);
		(*dataOut)[L"connected"] = new JSONValue(connected);
	}
	else {
		// not connected
		(*dataOut)[L"connected"] = new JSONValue(false);
		error = -1;
	}
	addCRErrorCode(error, errorOut, L"mfcs_queryRotaryAddress");
}

void PGMFC_API::mfcs_rotaryReset(NATIVE_HANDLE_TYPE nativeHandle, JSONObject* paras, JSONObject* dataOut, JSONObject* errorOut, wstring logFilename) {
	TWrite2Txt logger(logFilename, ENABLE_PGMFC_LOG);
	logger.writeString("[PGMFC core] mfcs_rotaryReset(");

	int paraIdx = 0;
	if (!j_findInt(paras, paraIdx, L"switch_type", logger)) { return; } int switch_type = j_parseInt(paras, paraIdx, L"switch_type", logger);
	if (!j_findInt(paras, paraIdx, L"mount_id", logger)) { return; } int mount_id = j_parseInt(paras, paraIdx, L"mount_id", logger);

	logger.writeLine(")");

	int error;
	if (nativeHandle != NULL) {
		error = native.mfcs_rotaryReset(nativeHandle, switch_type, mount_id);
	}
	else {
		// not connected
		error = -1;
	}
	addCRErrorCode(error, errorOut, L"mfcs_rotaryReset");
}

void PGMFC_API::mfcs_queryRotaryCurPos(NATIVE_HANDLE_TYPE nativeHandle, JSONObject* paras, JSONObject* dataOut, JSONObject* errorOut, wstring logFilename) {
	TWrite2Txt logger(logFilename, ENABLE_PGMFC_LOG);
	logger.writeString("[PGMFC core] mfcs_queryRotaryCurPos(");

	int paraIdx = 0;
	if (!j_findInt(paras, paraIdx, L"switch_type", logger)) { return; } int switch_type = j_parseInt(paras, paraIdx, L"switch_type", logger);
	if (!j_findInt(paras, paraIdx, L"mount_id", logger)) { return; } int mount_id = j_parseInt(paras, paraIdx, L"mount_id", logger);

	logger.writeLine(")");

	int error;
	if (nativeHandle != NULL) {
		unsigned short position;
		error = native.mfcs_queryRotaryCurPos(nativeHandle, switch_type, mount_id, position);
		(*dataOut)[L"position"] = new JSONValue(position);
	}
	else {
		// not connected
		(*dataOut)[L"position"] = new JSONValue(-601);
		error = -1;
	}
	addCRErrorCode(error, errorOut, L"mfcs_queryRotaryCurPos");
}

void PGMFC_API::mfcs_rotarySwitchTo(NATIVE_HANDLE_TYPE nativeHandle, JSONObject* paras, JSONObject* dataOut, JSONObject* errorOut, wstring logFilename) {
	TWrite2Txt logger(logFilename, ENABLE_PGMFC_LOG);
	logger.writeString("[PGMFC core] mfcs_rotarySwitchTo(");

	int paraIdx = 0;
	if (!j_findInt(paras, paraIdx, L"switch_type", logger)) { return; } int switch_type = j_parseInt(paras, paraIdx, L"switch_type", logger);
	if (!j_findInt(paras, paraIdx, L"mount_id", logger)) { return; } int mount_id = j_parseInt(paras, paraIdx, L"mount_id", logger);
	if (!j_findInt(paras, paraIdx, L"position", logger)) { return; } int position = j_parseInt(paras, paraIdx, L"position", logger);

	logger.writeLine(")");

	int error;
	if (nativeHandle != NULL) {
		error = native.mfcs_rotarySwitchTo(nativeHandle, switch_type, mount_id, position);
	}
	else {
		// not connected
		error = -1;
	}
	addCRErrorCode(error, errorOut, L"mfcs_rotarySwitchTo");
}

void PGMFC_API::mfcs_queryChannelStatus1(NATIVE_HANDLE_TYPE nativeHandle, JSONObject* paras, JSONObject* dataOut, JSONObject* errorOut, wstring logFilename) {
	TWrite2Txt logger(logFilename, ENABLE_PGMFC_LOG);
	logger.writeString("[PGMFC core] mfcs_queryChannelStatus1(");
	logger.writeLine(")");

	int error;
	if (nativeHandle != NULL) {
		error = native.mfcs_queryChannelStatus1(nativeHandle);
	}
	else {
		// not connected
		error = -1;
	}
	addCRErrorCode(error, errorOut, L"mfcs_queryChannelStatus1");
}

void PGMFC_API::mfcs_queryChannelStatus2(NATIVE_HANDLE_TYPE nativeHandle, JSONObject* paras, JSONObject* dataOut, JSONObject* errorOut, wstring logFilename) {
	TWrite2Txt logger(logFilename, ENABLE_PGMFC_LOG);
	logger.writeString("[PGMFC core] mfcs_queryChannelStatus2(");
	logger.writeLine(")");

	int error;
	if (nativeHandle != NULL) {
		error = native.mfcs_queryChannelStatus2(nativeHandle);
	}
	else {
		// not connected
		error = -1;
	}
	addCRErrorCode(error, errorOut, L"mfcs_queryChannelStatus2");
}

void PGMFC_API::mfcs_getCurChannelInfo(NATIVE_HANDLE_TYPE nativeHandle, JSONObject* paras, JSONObject* dataOut, JSONObject* errorOut, wstring logFilename) {
	TWrite2Txt logger(logFilename, ENABLE_PGMFC_LOG);
	logger.writeString("[PGMFC core] mfcs_getCurChannelInfo(");
	logger.writeLine(")");

	int error;
	if (nativeHandle != NULL) {
		int pump_status, run_time, wave_form;
		float max_value, min_value;
		error = native.mfcs_getCurChannelInfo(nativeHandle, &pump_status, &run_time, &wave_form, &max_value, &min_value);
		(*dataOut)[L"pump_status"] = new JSONValue(pump_status);
		(*dataOut)[L"run_time"] = new JSONValue(run_time);
		(*dataOut)[L"wave_form"] = new JSONValue(wave_form);
		(*dataOut)[L"max_value"] = new JSONValue(max_value);
		(*dataOut)[L"min_value"] = new JSONValue(min_value);
	}
	else {
		// not connected
		(*dataOut)[L"pump_status"] = new JSONValue(-701);
		(*dataOut)[L"run_time"] = new JSONValue(-702);
		(*dataOut)[L"wave_form"] = new JSONValue(-703);
		(*dataOut)[L"max_value"] = new JSONValue(-704);
		(*dataOut)[L"min_value"] = new JSONValue(-705);
		error = -1;
	}
	addCRErrorCode(error, errorOut, L"mfcs_getCurChannelInfo");
}

bool PGMFC_API::j_findInt(JSONObject* paras, int& idx, const wchar_t* name, TWrite2Txt& logger) {
	if ((*paras).find(name) == (*paras).end()) {
		logger.writeLine(L"{" + wstring(name) + L"} not found");
		return false;
	}
	if (!(*paras)[name]->IsNumber()) {
		logger.writeLine(L"{" + wstring(name) + L"} not int/number");
		return false;
	}
	return true;
}

int PGMFC_API::j_parseInt(JSONObject* paras, int& idx, const wchar_t* name, TWrite2Txt& logger) {
	int ret = (*paras)[name]->AsNumber();
	if (idx > 0) {
		logger.writeString(L",");
	}
	idx++;
	logger.writeString(TFormater::int2str(ret));
	return ret;
}

bool PGMFC_API::j_findFlt(JSONObject* paras, int& idx, const wchar_t* name, TWrite2Txt& logger) {
	return j_findInt(paras, idx, name, logger);
}

float PGMFC_API::j_parseFlt(JSONObject* paras, int& idx, const wchar_t* name, TWrite2Txt& logger) {
	return j_parseInt(paras, idx, name, logger);
}

bool PGMFC_API::j_findBul(JSONObject* paras, int& idx, const wchar_t* name, TWrite2Txt& logger) {
	if ((*paras).find(name) == (*paras).end()) {
		logger.writeLine(L"{" + wstring(name) + L"} not found");
		return false;
	}
	if (!(*paras)[name]->IsBool()) {
		logger.writeLine(L"{" + wstring(name) + L"} not bool");
		return false;
	}
	return true;
}

bool PGMFC_API::j_parseBul(JSONObject* paras, int& idx, const wchar_t* name, TWrite2Txt& logger) {
	bool ret = (*paras)[name]->AsBool();
	if (idx > 0) {
		logger.writeString(L",");
	}
	idx++;
	logger.writeString(TFormater::bool2str(ret));
	return ret;
}

void PGMFC_API::addCErrorCode(int code, JSONObject* obj, const wchar_t* name) {
	JSONObject codeObj;
	codeObj[L"error_code"] = new JSONValue(code);
	codeObj[L"message"] = new JSONValue(translateCErr(code, name));
	(*obj)[L"c_error"] = new JSONValue(codeObj);
}

void PGMFC_API::addCRErrorCode(int code, JSONObject* obj, const wchar_t* name) {
	JSONObject codeObj;
	codeObj[L"error_code"] = new JSONValue(code);
	codeObj[L"message"] = new JSONValue(translateCRErr(code, name));
	(*obj)[L"c__r_error"] = new JSONValue(codeObj);
}

wstring PGMFC_API::translateCErr(int cErr, const wchar_t* name) {
	if (cErr == 0) {
		return L"OK";
	}
	else if (cErr == 1) {
		return L"PGMFC not connected";
	}
	else if (cErr == 2) {
		return L"Fail Open Session";
	}
	else if (cErr == 3) {
		return L"Wrong channel";
	}

	else if (cErr == 100) {
		return L"Illegal Input";
	}
	else if (cErr == 101) {
		return L"Not a PGMFC controller";
	}
	else if (cErr == 200) {
		return L"No response";
	}
	else if (cErr == 201) {
		return L"No data found";
	}

	else if (cErr == -1) {
		return L"PGMFC simulation: " + wstring(name);
	}
	else {
		return L"Undefined";
	}
}

wstring PGMFC_API::translateCRErr(int cRErr, const wchar_t* name) {
	if (cRErr == 0) {
		return L"OK";
	}
	else if (cRErr == 200) {
		return L"No response";
	}
	else if (cRErr == 0x01) {
		return L"Frame error";
	}
	else if (cRErr == 0x02) {
		return L"Parameter error";
	}
	else if (cRErr == 0x03) {
		return L"Optical coupling error";
	}
	else if (cRErr == 0x04) {
		return L"=Motor is busy";
	}
	else if (cRErr == 0xfe) {
		return L"Task is suspened";
	}
	else if (cRErr == 0xff) {
		return L"Unkown error";
	}

	else if (cRErr == -1) {
		return L"PGMFC simulation: " + wstring(name);
	}
	else {
		return L"Undefined";
	}
}